package cn.tedu.ximart.server.service.impl;


import cn.tedu.ximart.server.ex.ServiceException;
import cn.tedu.ximart.server.mapper.AdminMapper;
import cn.tedu.ximart.server.mapper.AdminRoleMapper;
import cn.tedu.ximart.server.pojo.dto.AdminAddNewDTO;
import cn.tedu.ximart.server.pojo.dto.AdminLoginDTO;
import cn.tedu.ximart.server.pojo.entity.Admin;
import cn.tedu.ximart.server.pojo.entity.AdminRole;
import cn.tedu.ximart.server.pojo.vo.AdminListItemVO;
import cn.tedu.ximart.server.pojo.vo.AdminSimpleVO;
import cn.tedu.ximart.server.security.AdminDetails;
import cn.tedu.ximart.server.service.IAdminService;
import cn.tedu.ximart.server.utils.JwtUtils;
import cn.tedu.ximart.server.web.ServiceCode;
import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;

import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 品牌业务实现
 *
 * @author java@tedu.cn
 * @version 0.0.1
 */
@Slf4j
@Service
public class AdminServiceImpl implements IAdminService {

    @Autowired
    private PasswordEncoder passwordEncoder;
    @Autowired
    private AuthenticationManager authenticationManager;
    @Autowired
    private AdminMapper adminMapper;
    @Autowired
    private AdminRoleMapper adminRoleMapper;

    public AdminServiceImpl() {
        log.debug("创建业务逻辑对象：AdminServiceImpl");
    }

    @Override
    @Transactional
    public void addNew(AdminAddNewDTO adminAddNewDTO) {
        log.debug("开始处理添加管理员的业务，参数：{}", adminAddNewDTO);

        // 检查此用户名有没有被占用
        String username = adminAddNewDTO.getUsername();
        int count = adminMapper.countByUsername(username);
        if (count > 0) {
            String message = "添加管理员失败，用户名【" + username + "】已经被占用！";
            log.error(message);
            throw new ServiceException(ServiceCode.ERR_CONFLICT, message);
        }

        // 创建实体对象
        Admin admin = new Admin();

        // 将当前方法参数的值复制到实体类型的对象中
        BeanUtils.copyProperties(adminAddNewDTO, admin);
        // 补全属性值（不由客户端提交的属性的值，应该在插入之前补全）
        admin.setLoginCount(0);
        admin.setLastLoginIp(null);
        admin.setGmtLastLogin(null);

        // 将原密码从Admin对象中取出，加密后再存入到Admin对象中
        String rawPassword = admin.getPassword();
        String encodedPassword = passwordEncoder.encode(rawPassword);
        admin.setPassword(encodedPassword);

        // 将管理员数据写入到数据库中
        log.debug("即将向管理员表中写入数据：{}", admin);
        int rows = adminMapper.insert(admin);
        if (rows != 1) {
            String message = "添加管理员失败，服务器忙，请稍后再次尝试！【错误码：1】";
            log.error(message);
            throw new ServiceException(ServiceCode.ERR_INSERT, message);
        }

        // 插入管理员与角色的关联数据，使得以上添加的管理员是被分配了角色的
        AdminRole adminRole = new AdminRole();
        adminRole.setAdminId(admin.getId());
        adminRole.setRoleId(2L); // 暂时锁定为2号角色
        log.debug("即将向管理员与角色的关联表中写入数据：{}", adminRole);
        rows = adminRoleMapper.insert(adminRole);
        if (rows != 1) {
            String message = "添加管理员失败，服务器忙，请稍后再次尝试！【错误码：2】";
            log.error(message);
            throw new ServiceException(ServiceCode.ERR_INSERT, message);
        }
    }

    @Override
    public void deleteById(Long id) {
        log.debug("开始处理删除管理员的业务，参数：{}", id);

        // 检查尝试删除的管理员数据是否存在
        AdminSimpleVO queryResult = adminMapper.getSimpleById(id);
        if (queryResult == null) {
            String message = "删除管理员失败，尝试删除的数据不存在！";
            log.error(message);
            throw new ServiceException(ServiceCode.ERR_NOT_FOUND, message);
        }

        // 执行删除
        int rows = adminMapper.deleteById(id);
        if (rows != 1) {
            String message = "删除管理员失败，服务器忙，请稍后再次尝试！";
            log.error(message);
            throw new ServiceException(ServiceCode.ERR_NOT_FOUND, message);
        }
    }

    @Override
    public String login(AdminLoginDTO adminLoginDTO) {
        log.debug("开始处理管理员登录的业务，参数：{}", adminLoginDTO);

        // 调用AuthenticationManager执行Spring Security的认证
        Authentication authentication
                = new UsernamePasswordAuthenticationToken(
                adminLoginDTO.getUsername(), adminLoginDTO.getPassword());
        Authentication loginResult = authenticationManager.authenticate(authentication);

        // 以上调用的authenticate()方法是会抛出异常的方法，如果还能执行到此处，则表示用户名与密码是匹配的
        log.debug("登录成功！认证方法返回的数据类型：{}", loginResult.getClass().getName());
        log.debug("登录成功！认证方法返回的数据：{}", loginResult);
        // 从认证结果中获取Principal，本质上是User类型，且是UserDetailsService中loadUserByUsername()返回的结果
        log.debug("认认信息中的Principal类型：{}", loginResult.getPrincipal().getClass().getName());
        log.debug("认认信息中的Principal数据：{}", loginResult.getPrincipal());
        AdminDetails adminDetails = (AdminDetails) loginResult.getPrincipal();
        Long id = adminDetails.getId();
        log.debug("登录成功的管理员id：{}", id);
        String username = adminDetails.getUsername();
        log.debug("登录成功的管理员用户名：{}", username);
        Collection<GrantedAuthority> authorities = adminDetails.getAuthorities();
        log.debug("登录成功的管理员权限：{}", authorities);
        String authoritiesString = JSON.toJSONString(authorities);
        log.debug("将管理员权限转换为JSON：{}", authoritiesString);

        // 应该在此处生成JWT数据，向JWT中存入：id（暂无）, username, 权限
        Map<String, Object> claims = new HashMap<>();
        claims.put("id", adminDetails.getId());
        claims.put("username", adminDetails.getUsername());
        claims.put("authorities", authoritiesString);
        String jwt = JwtUtils.generate(claims);
        log.debug("生成JWT：{}", jwt);
        return jwt;
    }

    @Override
    public List<AdminListItemVO> list() {
        log.debug("开始处理查询管理员列表的业务");
        return adminMapper.list();
    }
}
